package com.wjr.braveheart.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.RelativeLayout;

import com.wjr.braveheart.R;

/**
 * Description:侧滑布局
 */
public class SlidingMenu extends HorizontalScrollView {
    // 菜单的宽度
    private int mMenuWidth;
    //侧滑菜单，阴影
    private View mMenuView, mShadowView;

    // GestureDetector 处理快速滑动,手势处理类
    private GestureDetector mGestureDetector;

    // 菜单是否打开
    private boolean mMenuIsOpen = false;

    // 是否拦截
    private boolean mIsIntercept = false;

    /**
     * 在代码中 new 的时候调用
     *
     * @param context
     */
    public SlidingMenu(Context context) {
        this(context, null);
    }

    /**
     * 写在布局文件中的时候调用
     *
     * @param context
     * @param attrs
     */
    public SlidingMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 写在布局文件中调用 但是会有style
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        // 初始化自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);

        float rightMargin = array.getDimension(
                R.styleable.SlidingMenu_menuRightMargin, dip2px(context, 50));
        // 菜单页的宽度是 = 屏幕的宽度 - 右边的一小部分距离（自定义属性）
        mMenuWidth = (int) (getScreenWidth(context) - rightMargin);
        array.recycle();

        mGestureDetector = new GestureDetector(context, mGestureListener);
    }


    // 1.宽度不对（乱套了），指定宽高
    @Override
    protected void onFinishInflate() {
        // 这个方法是布局解析完毕也就是 XML 布局文件解析完毕
        super.onFinishInflate();
        // 指定宽高 1.内容页的宽度是屏幕的宽度
        // 获取LinearLayout
        ViewGroup container = (ViewGroup) getChildAt(0);

        int childCount = container.getChildCount();
        if (childCount != 2) {
            throw new RuntimeException("SlidingMenu Can only contain two child Views!");
        }

        mMenuView = container.getChildAt(0);
        // 设置只能通过 LayoutParams ，
        ViewGroup.LayoutParams menuParams = mMenuView.getLayoutParams();
        menuParams.width = mMenuWidth;
        // 7.0 以下的手机必须采用下面的方式
        mMenuView.setLayoutParams(menuParams);

        // 2.菜单页的宽度是 屏幕的宽度 - 右边的一小部分距离（自定义属性）

        // 把内容布局单独提取出来，
        View oldContentView = container.getChildAt(1);
        ViewGroup.LayoutParams contentParams = oldContentView.getLayoutParams();
        container.removeView(oldContentView);
        // 然后在外面套一层阴影，
        RelativeLayout contentContainer = new RelativeLayout(getContext());
        contentContainer.addView(oldContentView);
        mShadowView = new View(getContext());
        mShadowView.setBackgroundColor(Color.parseColor("#55000000"));
        contentContainer.addView(mShadowView);
        // 最后在把容器放回原来的位置
        contentParams.width = getScreenWidth(getContext());
        contentContainer.setLayoutParams(contentParams);
        container.addView(contentContainer);
        mShadowView.setAlpha(0.0f);

        // 2. 初始化进来是关闭 发现没用
        //scrollTo(mMenuWidth,0); 加到 onFinishInflate() 方法里边再次尝试发现没什么用，这是因为我们的调用时机不对，
        // onFinishInflate()方法是在我们的 XML 布局文件解析完后调用的，这个时候布局虽然解析完了，但是并没有摆放呢，
        // 所以把滑动的代码放到 onLayout 即可。
        // scrollTo(mMenuWidth,0);
    }

    // 4. 处理右边的缩放，左边的缩放和透明度，需要不断的获取当前滚动的位置
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        // Log.e("TAG", "l -> " + l);// 变化是 mMenuWidth - 0
        // 算一个梯度值
        float scale = 1f * l / mMenuWidth;// scale 变化是 1 - 0

        // 控制阴影 0 - 1
        float alphaScale = 1 - scale;
        mShadowView.setAlpha(alphaScale);

        // 右边的缩放: 最小是 0.7f, 最大是 1f
        /*float rightScale = 0.7f + 0.3f * scale;
        // 设置右边的缩放,默认是以中心点缩放
        // 设置缩放的中心点位置
        ViewCompat.setPivotX(mContentView, 0);
        ViewCompat.setPivotY(mContentView, mContentView.getMeasuredHeight() / 2);
        ViewCompat.setScaleX(mContentView, rightScale);
        ViewCompat.setScaleY(mContentView, rightScale);

        // 菜单的缩放和透明度
        // 透明度是 半透明到完全透明  0.5f - 1.0f
        float leftAlpha = 0.5f + (1 - scale) * 0.5f;
        ViewCompat.setAlpha(mMenuView, leftAlpha);
        // 缩放 0.7f - 1.0f
        float leftScale = 0.7f + (1 - scale) * 0.3f;
        ViewCompat.setScaleX(mMenuView, leftScale);
        ViewCompat.setScaleY(mMenuView, leftScale);*/

        // 最后一个效果 退出这个按钮刚开始是在右边，安装我们目前的方式永远都是在左边
        // 设置平移，先看一个抽屉效果
        // ViewCompat.setTranslationX(mMenuView,l);
        // 平移 l*0.7f
        mMenuView.setTranslationX(0.8f * l);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        // 2. 初始化进来是关闭
        scrollTo(mMenuWidth, 0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        mIsIntercept = false;

        // 2. 处理事件拦截 + ViewGroup 事件分发的源码实践
        //    当菜单打开的时候，手指触 摸右边内容部分需要关闭菜单，还需要拦截事件（打开情况下点击内容页不会响应点击事件）
        if (mMenuIsOpen) {
            float currentX = ev.getX();
            if (currentX > mMenuWidth) {
                // 1.关闭菜单
//                closeMenu();
                // 2.子 View 不需要响应任何事件（点击和触摸），拦截子 View 的事件
                // 如果返回 true 代表我会拦截子View的事件，但是我会响应自己的 onTouch 事件
                mIsIntercept = true;
                return true;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    // 3.手指抬起是二选一，要么关闭要么打开
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // 如果有拦截就会执行自己的 onTouch
        if (mIsIntercept && ev.getAction() == MotionEvent.ACTION_UP) {
            mIsIntercept = false;
            closeMenu();
            return true;
        }


        if (mGestureDetector.onTouchEvent(ev)) {
            // 快速滑动触发了下面的就不要执行了
            return true;
        }
        // 1. 获取手指滑动的速率，当期大于一定值就认为是快速滑动 ， GestureDetector（系统提供好的类）
        // 2. 处理事件拦截 + ViewGroup 事件分发的源码实践
        //    当菜单打开的时候，手指触 摸右边内容部分需要关闭菜单，还需要拦截事件（打开情况下点击内容页不会响应点击事件）

        if (ev.getAction() == MotionEvent.ACTION_UP) {
            // 手指抬起时 ，根据我们当前滚动的距离来或者
            // 手指按下时的X的值是否大于mMenuWidth来判断是打开还是关闭菜单
            int currentScrollX = getScrollX();

            if (currentScrollX > mMenuWidth / 2) {
                // 关闭
                closeMenu();
            } else {
                // 打开
                openMenu();
            }
            // 确保 super.onTouchEvent() 不会执行
            return true;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 打开菜单 滚动到 0 的位置
     */
    private void openMenu() {
        // smoothScrollTo 有动画
        smoothScrollTo(0, 0);
        mMenuIsOpen = true;

    }

    /**
     * 关闭菜单 滚动到 mMenuWidth 的位置
     */
    private void closeMenu() {
        smoothScrollTo(mMenuWidth, 0);
        mMenuIsOpen = false;

    }

    /**
     * 7.切换菜单的状态
     */
    public void toggleMenu() {
        if (mMenuIsOpen) {
            closeMenu();
        } else {
            openMenu();
        }
    }

    private GestureDetector.OnGestureListener mGestureListener = new
            GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                    // 只关注快速滑动,只要快速就会回掉

                    // Bug  判断左右还是上下   只有左右快速滑动才切换
                    if (Math.abs(velocityY) > Math.abs(velocityX)) {
                        // 代表上下快速划  这个时候不做处理
                        return super.onFling(e1, e2, velocityX, velocityX);
                    }

                    // 条件 打开的时候往右边快速滑动切换（关闭），关闭的时候往左边快速滑动切换（打开）
                    Log.e("TAG", "velocityX -> " + velocityX);
                    // 快速往左边滑动的时候是一个负数，往右边滑动的时候是一个正数
                    if (mMenuIsOpen) {
                        // 打开的时候往右边快速滑动切换（关闭）
                        if (velocityX < 0) {
                            closeMenu();
                            return true;
                        }
                    } else {
                        // 关闭的时候往左边快速滑动切换（打开）
                        if (velocityX > 0) {
                            openMenu();
                            return true;
                        }
                    }
                    return super.onFling(e1, e2, velocityX, velocityY);
                }
            };

    /**
     * 获得屏幕高度
     *
     * @param context
     * @return
     */
    private int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * Dip into pixels
     */
    private int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
